package oa.hleast.common.web.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.JWSObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import oa.hleast.common.constant.AuthConstant;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class RequestUtils {


    public static HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    public static JSONObject getJwtPayload() {
        JSONObject jsonObject = null;
        String token = getRequest().getHeader(AuthConstant.AUTHORIZATION_KEY);
        System.out.println("token = " + token);
        if (StrUtil.isNotBlank(token)) {
            token = token.replace(AuthConstant.JWT_PREFIX, Strings.EMPTY);
            try {

                JWSObject jwsObject = JWSObject.parse(token);
                String jwtPayload = jwsObject.getPayload().toString();
//        JSONObject jsonObject = JSONUtil.parseObj(payload);

//        String jwtPayload = getRequest().getHeader(AuthConstant.JWT_PAYLOAD_KEY);
                log.info("jwtPayload = {}", jwtPayload);
                jsonObject = JSONUtil.parseObj(jwtPayload);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return jsonObject;
    }

    public static Long getUserId() {
        Long id = null;
        if (ObjectUtil.isNotNull(getJwtPayload())) {
            id = getJwtPayload().getLong(AuthConstant.JWT_USER_ID_KEY);
            log.info("user_id = {}", id);
        }
        return id;
    }

    /**
     * 获取JWT的载体中的clientId
     *
     * @return
     */
    public static String getClientId() {
        String clientId = getJwtPayload().getStr(AuthConstant.CLIENT_ID_KEY);
        return clientId;
    }

    /**
     * 获取登录认证的客户端ID
     * <p>
     * 兼容两种方式获取Oauth2客户端信息（client_id、client_secret）
     * 方式一：client_id、client_secret放在请求路径中
     * 方式二：放在请求头（Request Headers）中的Authorization字段，且经过加密，例如 Basic Y2xpZW50OnNlY3JldA== 明文等于 client:secret
     *
     * @return
     */
    @SneakyThrows
    public static String getAuthClientId() {
        String clientId;

        HttpServletRequest request = getRequest();

        // 从请求路径中获取
        clientId = request.getParameter(AuthConstant.CLIENT_ID_KEY);
        if (StrUtil.isNotBlank(clientId)) {
            log.info("从请求路径中获取 clientId = {}",clientId);
            return clientId;
        }

        // 从请求头获取
        String basic = request.getHeader(AuthConstant.AUTHORIZATION_KEY);
        basic = request.getHeader(AuthConstant.AUTHORIZATION_KEY);
        log.info("basic = {}",basic);
        if (StrUtil.isNotBlank(basic) && basic.startsWith(AuthConstant.BASIC_PREFIX)) {
            basic = basic.replace(AuthConstant.BASIC_PREFIX, Strings.EMPTY);
            String basicPlainText = new String(new BASE64Decoder().decodeBuffer(basic), "UTF-8");
            log.info("basic = {},basicPlainText = {}",basic,basicPlainText);
            //client:secret
            clientId = basicPlainText.split(":")[0];
            log.info("从请求头获取 clientId = {}",clientId);
        }
        return clientId;
    }


    public static List<Long> getRoleIds() {
        JSONObject jwtPayload = getJwtPayload();
        if (ObjectUtil.isEmpty(jwtPayload)) {
            return null;
        }
        List<String> list = jwtPayload.get(AuthConstant.JWT_AUTHORITIES_KEY, List.class);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<Long> authorities = list.stream().map(Long::valueOf).collect(Collectors.toList());
        return authorities;
    }
}
